﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Media;


namespace MainGame.GameSound
{

  public interface ISoundManager<T>
  {
    void PlaySound(T sound);

    void StopAllSounds();

    // The sound effects volume
    float SfxVolume { get; }
  }

  public abstract class SoundManager<T> : Microsoft.Xna.Framework.GameComponent, MainGame.GameSound.ISoundManager<T>
  {
    // Sound array
    protected SoundEffect[] soundLibrary;
    protected const int MaxSounds = 32;

    // Played sounds list
    protected SoundEffectInstance[] playingSounds;

    // The sound effects volume
    public float SfxVolume { get; private set; }


    public SoundManager(Game game)
      : base(game) 
    {
      game.Services.AddService(typeof(ISoundManager<T>), this);
    }

    protected override void Dispose(bool disposing)
    {
      Game.Services.RemoveService(typeof(ISoundManager<T>));
      base.Dispose(disposing);
    }

    public override void Initialize()
    {
      //soundLibrary = new SoundEffect[MaxSounds];
      playingSounds = new SoundEffectInstance[MaxSounds];
      base.Initialize();
    }

    public override void Update(GameTime gameTime)
    {
      // Keep the sound instances collection updated
      for (int i = 0; i < playingSounds.Length; ++i)
      {
        if (playingSounds[i] != null && playingSounds[i].State == SoundState.Paused)
        {
          playingSounds[i].Dispose();
          playingSounds[i] = null;
        }
      }

      base.Update(gameTime);
    }


    public abstract void PlaySound(T sound);

    /// <summary>
    /// Stop all playing sounds
    /// </summary>
    public void StopAllSounds()
    {
      for (int i = 0; i < playingSounds.Length; ++i)
      {
        if (playingSounds[i] != null)
        {
          playingSounds[i].Stop();
          playingSounds[i].Dispose();
          playingSounds[i] = null;
        }
      }
    }

    /// <summary>
    /// Add a new played sound to the playing sounds list
    /// </summary>
    /// <param name="sndInst">The sound instance to add to the list</param>
    protected void AddToPlayingQueue(SoundEffectInstance sndInst)
    {
      int nextAvailableIdx = GetAvailableSoundIndex();
      if (nextAvailableIdx != -1)
        playingSounds[nextAvailableIdx] = sndInst;
    }

    /// <summary>
    /// Get the next available index in the sound instances collection
    /// </summary>
    /// <returns>The first available position in the sound instances collection</returns>
    private int GetAvailableSoundIndex()
    {
      for (int i = 0; i < MaxSounds; ++i)
      {
        if (playingSounds[i] == null)
          return i;
      }
      return -1;
    }

  }
}
